from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

from random import choice
from itertools import cycle

# 第三周 第一节 中点法画圆


class MyPyOpenGLTest:
    # 初始化OpenGL环境，指定显示模式以及用于绘图的函数
    def __init__(self, width=640, height=480,
                 title='中点算法画圆'.encode('gbk')):
        glutInit(argv)
        # 使用RGBA颜色、双缓冲
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        # 设置图形窗口初始大小和位置，然后创建图形窗口，顺序不能变
        glutInitWindowSize(width, height)
        glutInitWindowPosition(400, 200)

        glutCreateWindow(title)
        # 指定绘制图形时执行的方法
        glutDisplayFunc(self.draw)
        # 指定调整窗口大小时执行的方法
        glutReshapeFunc(self.reshape)

        # 指定鼠标按下与抬起执行的方法
        # glutMouseFunc(self.mouse_downup)

        # 指定鼠标移动时执行的方法
        # glutMotionFunc(self.mouse_move)

        # 键盘上ASCII码键时执行的方法
        glutKeyboardFunc(self.ascii_key)


        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        # 基本图元类型
        self.modes = cycle((GL_POINTS,
                            GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP,
                            GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN,
                            GL_QUADS, GL_QUAD_STRIP,
                            GL_POLYGON))

        # 顶点坐标
        self.points = ((300, 300), (300, 500), (400, 600), (450, 400),
                        (450, 300), (550, 280), (400, 120), (300, 100),
                        (280, 230), (200, 150), (100, 230), (100, 350),)

        # 是否填充多边形内部，默认只填充正面
        self.fill = True
        # 只填充正面还是双面填充， 默认只填充正面
        self.both_or_font = GL_FRONT

        # 多边形的正面的顶点方向，莫仍逆时针
        self.direction = GL_CCW

        # 指定系统空闲时执行的方法
        # glutIdleFunc(self.draw)
        # 进一步初始化，完成个性化设置
        # self.InitGL(width, height)

    # 根据特定的需要，进一步完成OpenGL的初始化
    def InitGL(self, width, height):
        # 初始化窗口背景为白色
        glClearColor(1.0, 1.0, 1.0, 1.0)
        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        # 加载单位矩阵，重置
        glLoadIdentity()
        gluOrtho2D(0, width, 0, height)
        # 切换到模型观察矩阵
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    # 调整图形窗口大小时执行的方法
    def reshape(self, w, h):

        # 设置视口/视区的左下角x、y坐标以及窗口宽度和高度
        # 视口是最终用来显示图形的区域
        # glViewport(0, 0, w, h)
        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # 设置世界窗口的左下角x坐标、右上角x坐标、左下角y坐标、右上角y坐标
        # 这是需要显示到视口的图形区域
        # gluOrtho2D(0, w, 0, h)
        # 设置窗口
        gluOrtho2D(0, w, h, 0)
        # 修改为下面的大小可以看到直线段被放大后像素离散的状态

        # 切换到模型观察矩阵
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    def ascii_key(self, key, x, y):
        if key ==b' ':
            self.current_mode = next(self.modes)
        elif key ==b's':
            self.fill = not self.fill
        elif key == b'd':
            # 切换正面顶点的方向，顺时针或逆时针
            if self.direction == GL_CW:
                self.direction =GL_CCW
            elif self.direction ==GL_CCW:
                self.direction = GL_CW
        elif key == b'f':
            if self.both_or_font == GL_FRONT_AND_BACK:
                self.both_or_font = GL_FRONT
            elif self.both_or_font == GL_FRONT:
                self.both_or_font = GL_FRONT_AND_BACK
        else:
            return

        # 强制刷新屏幕
        glutPostRedisplay()

    # 自己的绘图方法，本程序的关键
    def draw(self):
        # 初始化窗口背景为白色
        glClearColor(1.0, 1.0, 1.0, 1.0)

        # 每次绘制图形之前清除颜色缓冲区和深度缓冲区中的信息
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 切换到模型观察矩阵，才能正确绘制图形
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        # 黑色

        glColor3f(0, 0, 0)
        glLineWidth(3)
        glPointSize(3)
        glColor3f(0, 0, 0)

        if not self.fill:
            # 只绘制多边形线条
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        else:
            # 设置多边形正面顶点方向、
            glFrontFace(self.direction)
            # 填充多边形内部区域
            glPolygonMode(self.both_or_font, GL_FILL)
        # 设置图元类型，开始绘制
        glBegin(self.current_mode)
        for point in self.points:
            glVertex2f(point)
        glEnd()
        glColor3f(1, 0, 0)
        glRasterPos2f(5, 25)
        for ch in str(self.current_mode):

            glutBitmapCharacter(GLUT_WINDOW_ACCUM_BLUE_SIZE, ord(ch))

        # 在每个点的右下方显示顶点编号
        for i, point in enumerate(self.points, start = 1):
            glRasterPos2f(point[0]+5, point[1]+5)
            for ch in str(1):
                glutBitmapCharacter(GLUT_WINDOW_ACCUM_BLUE_SIZE,ord(ch))




        # glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)



        # self.draw_circle_Mid(0, 0, 90, (0, 1, 0))
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    # 创建窗口对象，启动消息主循环
    MyPyOpenGLTest().mainloop()
